package com.example.chat.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.chat.domain.dto.VerifyForm;
import com.example.chat.domain.entity.Friends;
import com.example.chat.domain.entity.Friendship;
import com.example.chat.domain.entity.GroupInvite;
import com.example.chat.domain.entity.User;
import com.example.chat.domain.vo.FriendsAndLetterVo;
import com.example.chat.domain.vo.InviteCountVo;
import com.example.chat.domain.vo.UserInfoVo;
import com.example.chat.mapper.FriendshipMapper;
import com.example.chat.result.Result;
import com.example.chat.service.FriendshipService;
import com.example.chat.service.GroupInviteService;
import com.example.chat.service.UserService;
import com.example.chat.utils.Pinyin4jUtil;
import com.example.chat.utils.RedisConstants;
import com.example.chat.utils.UserHolder;
import com.example.chat.domain.vo.QueryUserVo;
import jakarta.annotation.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class FriendshipServiceImpl extends ServiceImpl<FriendshipMapper, Friendship> implements FriendshipService {

    @Resource
    private UserService userService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private GroupInviteService groupInviteService;

    private static final DefaultRedisScript<Void> test = new DefaultRedisScript<>();
    private static final DefaultRedisScript<Void> remove = new DefaultRedisScript<>();
    private static final DefaultRedisScript<List> maybeKnow = new DefaultRedisScript<>();

    static {
        test.setLocation(new ClassPathResource("scripts/passVerify.lua"));
        test.setResultType(Void.class);
        remove.setLocation(new ClassPathResource("scripts/removeFriend.lua"));
        remove.setResultType(Void.class);
        maybeKnow.setLocation(new ClassPathResource("scripts/friend/maybeKnowUser.lua"));
        maybeKnow.setResultType(List.class);
    }

    @Override
    public Result getByPhone(String phone) {
        String s = stringRedisTemplate.opsForValue().get(RedisConstants.USER_PHONE + phone);
        if(StrUtil.isBlank(s) && s != null){
            return Result.ok("该用户未注册");
        }
        //1、查询该手机号的用户
        User user = userService.lambdaQuery()
                .eq(User::getPhone, phone)
                .select(User::getId, User::getUserName, User::getIcon).one();
        if(user == null){
            //解决缓存穿透并设置过期时间
            stringRedisTemplate.opsForValue()
                    .set(RedisConstants.USER_PHONE+phone,"",RedisConstants.TIME_ONE_MINUTES,TimeUnit.MINUTES);
            return Result.ok("该用户未注册");
        }
        //2、封装返回给前端的数据
        Long userId = user.getId();
        QueryUserVo queryUserVo = new QueryUserVo();
        queryUserVo.setId(userId);
        queryUserVo.setUserName(user.getUserName());
        queryUserVo.setIcon(user.getIcon());

        //3、设置与该用户status状态,0用户自己 1已是好友关系,2.已有请求中,3陌生用户
        Long currentId = UserHolder.getCurrentId();
        if(userId.equals(currentId)){
            //用户自己
            queryUserVo.setStatus(0);
            return Result.ok(queryUserVo);
        }
        //3.1、判断是否已是好友关系
        Boolean isSuccess = stringRedisTemplate.opsForSet()
                .isMember(RedisConstants.ADDRESSLIST_FRIENDS + user.getId(), currentId.toString());
        if(isSuccess){
            queryUserVo.setStatus(1);
            return Result.ok(queryUserVo);
        }
        //判断是否已有请求
        Long count1 = lambdaQuery()
                .in(Friendship::getSendId, List.of(currentId,userId))
                .in(Friendship::getReceiveId, List.of(currentId,userId))
                .in(Friendship::getStatus,List.of(0,2)).count();
        if(count1 > 0){
            //与该用户申请好友中,
            queryUserVo.setStatus(2);
            return Result.ok(queryUserVo);
        }
        //陌生用户
        queryUserVo.setStatus(3);
        return Result.ok(queryUserVo);
    }

    @Override
    public Result byStudentId(String studentId) {
        String s = stringRedisTemplate.opsForValue().get(RedisConstants.STUDENT_ID + studentId);
        if(StrUtil.isBlank(s) && s != null){
            return Result.ok("该用户未注册");
        }
        //1、查询该学号的用户
        User user = userService.lambdaQuery()
                .eq(User::getStudentId, studentId)
                .select(User::getId, User::getUserName, User::getIcon).one();
        if(user == null){
            //解决缓存穿透并设置过期时间
            stringRedisTemplate.opsForValue()
                    .set(RedisConstants.STUDENT_ID+studentId,"",RedisConstants.TIME_ONE_MINUTES,TimeUnit.MINUTES);
            return Result.ok("该用户未注册");
        }
        //2、封装返回给前端的数据
        Long userId = user.getId();
        QueryUserVo queryUserVo = new QueryUserVo();
        queryUserVo.setId(userId);
        queryUserVo.setUserName(user.getUserName());
        queryUserVo.setIcon(user.getIcon());

        //3、设置与该用户status状态,0用户自己 1已是好友关系,2.已有请求中,3陌生用户
        Long currentId = UserHolder.getCurrentId();
        if(userId.equals(currentId)){
            //用户自己
            queryUserVo.setStatus(0);
            return Result.ok(queryUserVo);
        }

        //3.1、判断是否已是好友关系
        Boolean isSuccess = stringRedisTemplate.opsForSet()
                .isMember(RedisConstants.ADDRESSLIST_FRIENDS + user.getId(), currentId.toString());
        if(isSuccess){
            queryUserVo.setStatus(1);
            return Result.ok(queryUserVo);
        }
        //判断是否已有请求
        Long count1 = lambdaQuery()
                .in(Friendship::getSendId, List.of(currentId,userId))
                .in(Friendship::getReceiveId, List.of(currentId,userId))
                .in(Friendship::getStatus,List.of(0,2)).count();
        if(count1 > 0){
            //与该用户申请好友中,
            queryUserVo.setStatus(2);
            return Result.ok(queryUserVo);
        }
        //陌生用户
        queryUserVo.setStatus(3);
        return Result.ok(queryUserVo);
    }

    @Override
    public Result addFriend(Long id) {
        Long currentId = UserHolder.getCurrentId();
        Friendship friendship1 = lambdaQuery().eq(Friendship::getStatus, 3)
                .in(Friendship::getSendId, List.of(currentId, id))
                .in(Friendship::getReceiveId, List.of(currentId, id)).one();
        if(friendship1 != null){
            lambdaUpdate().eq(Friendship::getId,friendship1.getId())
                    .set(Friendship::getStatus,2)
                    .set(Friendship::getSendId,currentId)
                    .set(Friendship::getReceiveId,id)
                    .update();
            return Result.ok();
        }
        Friendship friendship = new Friendship();
        friendship.setSendId(currentId);
        friendship.setReceiveId(id);
        boolean success = save(friendship);
        if(!success){
            return Result.fail("添加失败");
        }
        return Result.ok("添加成功");
    }

    @Override
    public Result getNewFriendList() {
        //1.查询全部和自己有关的记录
        Long currentId = UserHolder.getCurrentId();
        List<Friendship> friendships = lambdaQuery()
                .notIn(Friendship::getStatus,1)
                .eq(Friendship::getReceiveId, currentId)
                .or()
                .notIn(Friendship::getStatus,1)
                .eq(Friendship::getSendId, currentId)
                .orderByDesc(Friendship::getCreateTime).list();

        if(friendships == null || friendships.size() < 1){
            return Result.ok(Collections.emptyList());
        }
        //用于返回的结果集
        List<QueryUserVo> queryUserVos = new ArrayList<>();
        for (Friendship friendship : friendships) {
            if(currentId.equals(friendship.getReceiveId())){
                User user = userService.getById(friendship.getSendId());
                QueryUserVo queryUserVo = BeanUtil.copyProperties(user, QueryUserVo.class);
                queryUserVo.setStatus(friendship.getStatus());
                queryUserVos.add(queryUserVo);
            }else{
                User user = userService.getById(friendship.getReceiveId());
                QueryUserVo queryUserVo = BeanUtil.copyProperties(user, QueryUserVo.class);
                Integer status = (friendship.getStatus() == 0 || friendship.getStatus() == 2) ? 4 : friendship.getStatus();
                queryUserVo.setStatus(status);
                queryUserVos.add(queryUserVo);
            }
        }
        return Result.ok(queryUserVos);
    }

    @Override
    public Result passOrIgnore(VerifyForm verifyForm) {

        Long currentId = UserHolder.getCurrentId();
        Long userId = verifyForm.getId();
        //通过好友验证
        if(verifyForm.getType() == 1){
            boolean success = lambdaUpdate()
                    .eq(Friendship::getSendId, userId)
                    .eq(Friendship::getReceiveId,currentId)
                    .set(Friendship::getStatus, 1).update();
            if(success){
                String currentIdStr = String.valueOf(currentId);
                String userIdStr = String.valueOf(userId);
                String time = LocalDateTime.now()
                        .format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
                String timestamp = String.valueOf(System.currentTimeMillis());
                String content = "";
                String tip = "0";
                List<String> keys = List.of(currentIdStr,userIdStr);
                List<String> args = List.of(currentIdStr,userIdStr,timestamp,content,tip,time);
                stringRedisTemplate.execute(test,keys,args.toArray());
                return Result.ok();
            }
            return Result.fail("操作失败");
        }
        //忽略好友验证
        boolean success = lambdaUpdate()
                .eq(Friendship::getSendId, userId)
                .eq(Friendship::getReceiveId,currentId)
                .set(Friendship::getStatus,0).update();
        if(!success){
            return Result.fail("操作失败");
        }
        return Result.ok();
    }

    @Override
    public Result getVerifyCount() {
        Long currentId = UserHolder.getCurrentId();
        Long friendInviteCount = lambdaQuery()
                .eq(Friendship::getReceiveId, currentId)
                .eq(Friendship::getStatus, 2).count();

        Long groupInviteCount = groupInviteService.lambdaQuery()
                .eq(GroupInvite::getInvitee, currentId)
                .eq(GroupInvite::getStatus, 2).count();
        InviteCountVo countVo = InviteCountVo.builder()
                .friendInviteCount(friendInviteCount)
                .groupInviteCount(groupInviteCount)
                .build();
        return Result.ok(countVo);
    }

    @Override
    public Result getFriendsList() {
        Long currentId = UserHolder.getCurrentId();
        String list = stringRedisTemplate.opsForValue().get(RedisConstants.ADDRESSLIST_FriendList + currentId);
        if(!StrUtil.isEmptyIfStr(list)){
            List<FriendsAndLetterVo> groupedUsers = JSONUtil.toList(list, FriendsAndLetterVo.class);
            return Result.ok(groupedUsers);
        }
        Set<String> members = stringRedisTemplate.opsForSet().members(RedisConstants.ADDRESSLIST_FRIENDS + currentId);
        if(members == null || members.size() < 1){
            return Result.ok(Collections.emptyList());
        }
        List<Long> ids = members.stream().map(Long::valueOf).collect(Collectors.toList());
        List<User> users = userService.lambdaQuery().in(User::getId, ids).list();
        List<Friends> groupUserVos = BeanUtil.copyToList(users, Friends.class);

        List<FriendsAndLetterVo> groupedUsers = groupByLetter(groupUserVos);

        stringRedisTemplate.opsForValue().set(RedisConstants.ADDRESSLIST_FriendList+currentId, JSONUtil.toJsonStr(groupedUsers));
        stringRedisTemplate.expire(RedisConstants.ADDRESSLIST_FriendList+currentId,RedisConstants.TIME_THIRTY_MINUTES, TimeUnit.MINUTES);
        return Result.ok(groupedUsers);
    }

    @Override
    public Result deleteById(Long id) {
        Long currentId = UserHolder.getCurrentId();
        boolean isRemove = remove(new QueryWrapper<Friendship>().lambda().in(Friendship::getSendId, List.of(currentId, id))
                .in(Friendship::getReceiveId, List.of(currentId, id)));
        if(isRemove){
            List<String> keys = List.of(currentId.toString(),id.toString());
            stringRedisTemplate.execute(FriendshipServiceImpl.remove,keys);
        }
        return Result.ok();
    }

    @Override
    public Result maybeKnow() {
        Long currentId = UserHolder.getCurrentId();
        List<String> keys = List.of(currentId.toString());
        List userIds2 = stringRedisTemplate.execute(maybeKnow, keys);
        List<Long> userIds = new ArrayList<>();
        //String转Long
        for (Object user : userIds2) {
            userIds.add(Long.valueOf(user.toString()));
        }
        if(userIds !=null && userIds.size() > 0){
            List<Long> ids;
            int count = 20;
            int size = userIds.size();
            //随机获取id,若小于count则全取
            if (size <= count) {
                ids = new ArrayList<>(userIds);
            } else {
                Random random = new Random();
                Set<Long> selectedIds = new HashSet<>();
                for (int i = 0; i < 10; i++) {
                    int randomIndex = random.nextInt(size);
                    selectedIds.add(userIds.get(randomIndex));
                }
                ids = new ArrayList<>(selectedIds);
            }

            //查找是否与ids中的用户存在已有申请(0已忽略，2申请中)
            QueryWrapper<Friendship> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("status", Arrays.asList(0, 2));
            queryWrapper.and(qw -> qw
                            .eq("send_user", currentId)
                            .in("receive_user", ids)
                    )
                    .or(qw -> qw
                            .eq("receive_user", currentId)
                            .in("send_user", ids)
                    );

            //去除已有申请的id
            List<Friendship> list = list(queryWrapper);
            Set<Long> set = new HashSet<>(ids);
            for (int i = 0; i < list.size(); i++) {
                Long sendId = list.get(i).getSendId();
                if(set.contains(Long.valueOf(sendId))){
                    set.remove(sendId);
                }
                Long receiveId = list.get(i).getReceiveId();
                if(set.contains(Long.valueOf(receiveId))){
                    set.remove(receiveId);
                }
            }

            //查询用户信息
            List<User> users = userService.listByIds(set);
            List<UserInfoVo> userInfoVos = BeanUtil.copyToList(users, UserInfoVo.class);
            return Result.ok(userInfoVos);
        }
        return Result.ok(Collections.EMPTY_LIST);
    }

    private List<FriendsAndLetterVo> groupByLetter(List<Friends> groupUserVos) {
        Map<Character, List<Friends>> groupedMap = new TreeMap<>();
        for (Friends groupUserVo : groupUserVos) {
            char firstChar = groupUserVo.getUserName().charAt(0);
            char firstLetter;
            if (Character.isLetter(firstChar)) {
                if(Pinyin4jUtil.isChineseCharacter(firstChar)){
                    firstChar = Pinyin4jUtil.getPinyin(String.valueOf(firstChar)).charAt(0);
                }
                firstLetter = Character.toUpperCase(firstChar);
            } else {
                firstLetter = '#';
            }
            groupedMap.computeIfAbsent(firstLetter, k -> new ArrayList<>()).add(groupUserVo);
        }
        // 将分组结果转换为 List，并确保 '#' 分组放在最后
        List<FriendsAndLetterVo> collect = groupedMap.entrySet().stream()
                .map(entry -> new FriendsAndLetterVo(entry.getKey(),entry.getValue()))
                .sorted(Comparator.comparingInt(entry -> entry.getLetter() == '#' ? 26 : entry.getLetter() - 'A'))
                .collect(Collectors.toList());
        return collect;
    }
}
